package org.springframework.security.core.context;

import java.util.function.Supplier;

import org.springframework.util.Assert;

/**
 * @author Dillon
 * @date 2024/6/28
 * @slogan 致敬大师 致敬未来的你
 * @desc springSecurity 登录成功默认策略实现类
 * threadLocal
 */
final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {

	/**
	 * threadLocal 存储缓存对象
	 */
	private static final ThreadLocal<Supplier<SecurityContext>> contextHolder = new ThreadLocal<>();

	/**
	 * 清除 SecurityContext 缓存
	 */
	@Override
	public void clearContext() {
		contextHolder.remove();
	}

	/**
	 * 获取 SecurityContext 缓存
	 * 从提供接口中国获取，如果不存在，则初始化一个空 SecurityContext
	 *
	 * @return SecurityContext
	 */
	@Override
	public SecurityContext getContext() {
		return getDeferredContext().get();
	}

	/**
	 * 获取一个延时加载的  SecurityContext
	 * 如果不存在，则初始化一个空的 SecurityContext
	 *
	 * @return Supplier<SecurityContext>
	 */
	@Override
	public Supplier<SecurityContext> getDeferredContext() {
		Supplier<SecurityContext> result = contextHolder.get();
		if (result == null) {
			SecurityContext context = createEmptyContext();
			result = () -> context;
			contextHolder.set(result);
		}
		return result;
	}

	/**
	 * 设置  SecurityContext
	 *
	 * @param context SecurityContext
	 */
	@Override
	public void setContext(SecurityContext context) {
		Assert.notNull(context, "只允许非空的 SecurityContext 实例");
		contextHolder.set(() -> context);
	}

	/**
	 * 设置一个延时加载的  SecurityContext
	 * 在第一次调用该方法时进行  SecurityContext 获取
	 *
	 * @param deferredContext SecurityContext
	 */
	@Override
	public void setDeferredContext(Supplier<SecurityContext> deferredContext) {
		Assert.notNull(deferredContext, "只允许 非空 的Supplier 实例");
		Supplier<SecurityContext> notNullDeferredContext = () -> {
			SecurityContext result = deferredContext.get();
			Assert.notNull(result, "不允许返回空的Supplier<SecurityContext>");
			return result;
		};
		contextHolder.set(notNullDeferredContext);
	}

	/**
	 * 创建 SecurityContext 默认实现 SecurityContextImpl
	 *
	 * @return SecurityContextImpl
	 */
	@Override
	public SecurityContext createEmptyContext() {
		return new SecurityContextImpl();
	}

}
